/**
 * 
 */
package org.dragonfire.config;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Scanner;

import org.dragonfire.util.DString;

/**
 * @author Darth Android
 * @date Aug 19, 2007
 */
public class INIConfig extends Config {

	private HashMap<String, HashMap<String, String>> data = new HashMap<String, HashMap<String, String>>();

	public INIConfig() {
		// default constructor
	}

	public INIConfig(InputStream is) {
		importFile(is);
	}

	public INIConfig(String file) {
		FileInputStream fis;
		try {
			fis = new FileInputStream(file);
			importFile(fis);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public INIConfig(Config conf) {
		importFile(conf);
	}

	@Override
	public String[] getSections(String... path) {
		// if it's a root path, return all sections
		if (path == null || path.length == 0 || (path.length == 1 && (path[0].equals("") || path[0] == null)))
			return data.keySet().toArray(new String[data.size()]);
		// else return null set
		return new String[0];
	}

	@Override
	public String[] getKeys(String... path) {
		// validate path
		if (path == null || path.length == 0 || path[0] == null)
			path = new String[] {
				""
			};
		// INI files are flat, so return an empty set for a request of a deeper
		// section
		if (path.length > 1)
			return new String[0];
		String section = path[0];
		// case insensitive
		section = section.toLowerCase();
		// return empty set for undefined section
		if (data.get(section) == null)
			return new String[0];
		// return the keyset for the requested section
		return data.get(section).keySet().toArray(new String[0]);
	}

	@Override
	public String getValue(String... path) {
		// validate params
		if (path == null || path.length == 0 || path.length > 2)
			return null;
		if ((path.length == 2 && path[1] == null) || path[0] == null)
			return null;
		// determine section and key
		String section = "";
		String key = path[0];
		if (path.length == 2) {
			section = path[0];
			key = path[1];
		}
		// case insensitive
		key = key.toLowerCase();
		section = section.toLowerCase();
		// return null for undefined sections
		if (data.get(section) == null)
			return null;
		// return the value
		return data.get(section).get(key);
	}

	@Override
	public void putValue(String value, String... path) {
		// validate params
		if (path == null || path.length == 0 || path.length > 2)
			throw new IllegalArgumentException("Invalid path");
		if (value == null)
			value = "";
		String key = path[path.length - 1];
		String section = "";
		if (path.length == 2)
			section = path[0];
		// make section & key case insensitive
		section = section.toLowerCase();
		key = key.toLowerCase();
		// insert
		if (data.get(section) == null)
			data.put(section, new HashMap<String, String>());
		data.get(section).put(key, value);
	}

	@Override
	public void writeFile(OutputStream stream) {
		// TODO Auto-generated method stub
	}

	@Override
	public void importFile(InputStream stream) {
		// validate input
		if (stream == null)
			throw new NullPointerException("Stream may not be null.");
		Scanner in = new Scanner(stream);
		String currSection = "";
		while (in.hasNextLine()) {
			// read in the current line
			String line = in.nextLine();
			// check if it's a comment & skip it if it is
			if (line.matches("\\s*\\#.*"))
				continue;
			// check if it's a section header & process it
			if (line.matches("\\s*\\[.*\\]\\s*")) {
				line = DString.trim(line);
				line = line.substring(1, line.length() - 1);
				currSection = line;
				continue;
			}
			// skip over blank lines
			if (line.matches("\\s*"))
				continue;
			// process the line
			String[] parts = line.split("=", 2);
			String key = parts[0];
			String value = parts.length > 1 ? parts[1] : "";
			// insert the key/value
			putValue(value, currSection, key);
		}
	}

	@Override
	public void importFile(Config conf) {
		// validate params
		if (conf == null)
			throw new NullPointerException("conf cannot be null");
		// loop through all sections
		String[] sections = conf.getSections();
		for (String section : sections) {
			// loop through all keys
			String[] keys = conf.getKeys(section);
			for (String key : keys) {
				// insert value
				putValue(conf.getValue(section, key));
			}
		}
	}
}
